Vue3 + jsPlumb 您所在的位置:网站首页 vue3 dom更新 Vue3 + jsPlumb

Vue3 + jsPlumb

2023-04-25 00:36| 来源: 网络整理| 查看: 265

需求

目标:两组数据,分为两个列表展示,把对应的数据进行关联 关联方式:从左边列表拖拽出一条线关联到右边列表,一进一出,一一对应,无对应关系可不进行对应

选型

看了一些库,很多看起来都不支持类似功能(没有相关demo演示) 最终选定两个库:jsPlumb 和 antv G6

G6: 左右列表在G6内部生成,支持类型比较局限,控制显示内容的字段label好像只支持string,不支持自定义dom,灵活性不够,不能自定义关联的操作按钮

jsPlumb:可以自定义dom,通过id绑定的方式,与dom进行关联,相对灵活,操作按钮也可以自定义添加

使用 安装依赖:yarn add jsplumb 自定义配置 + 含义: // jsPlumb默认配置 jsPlumbSetting: { Container: "helen", // 在指定范围内划线,不能超出此范围,以id确定范围 // 设置锚点类型:静态锚点,动态锚点,周边锚点,连续锚点【 https://docs.jsplumbtoolkit.com/toolkit/6.x/lib/anchors 】 // Anchors: [ // "Continuous", // "Top","TopCenter","TopRight", "TopLeft", "Right", "RightMiddle", "Bottom", "BottomCenter", "BottomRight", "BottomLeft", "Left", "LeftMiddle","AutoDefault","Perimeter","Continuous" ], // 设置连线的样式:StateMachine、Flowchart,Bezier、Straight【 https://docs.jsplumbtoolkit.com/toolkit/6.x/lib/connectors 】 Connector: ["Straight", { gap: 5 }], // gap: 与端点间的距离; stub: 线出发多远开始弯折 // 鼠标是否拖动删除线 ConnectionsDetachable: true, // 删除线的时候节点不删除 DeleteEndpointsOnDetach: true, // 连线的两端端点类型:矩形 Rectangle;圆形Dot; eight: 矩形的高 ,idth: 矩形的宽 Endpoint: ["Dot", { radius: 5, cssClass: "yellow" }], //radius hoverClass:不能是局部样式 cssClass:不能是局部样式 // 线端点的样式: 不支持多个配置参数EndpointStyles // EndpointStyle: { fill: "skyblue", radius: 3 }, // 连线样式 PaintStyle: { stroke: "#000000", strokeWidth: 1, outlineStroke: "red", // 设定线外边的颜色 outlineWidth: 0, // 设定线外边的宽,单位px }, // 设置所有箭头的样式, Overlays绘制连线箭头 ConnectionOverlays: [ [ "Arrow", { // 设置参数可以参考中文文档 width: 8, // 箭头尾部的宽度 length: 8, // 从箭头的尾部到头部的距离 location: 1, // 位置,建议使用0~1之间 // direction: 1, // 方向,默认值为1(表示向前),可选-1(表示向后) // foldback: 0.623, // 折回,也就是尾翼的角度,默认0.623,当为1时,为正三角 // paintStyle: { stroke: "#999", fill: "#999" }, // 箭头样式 }, ], ], // 绘制图的模式 svg、canvas RenderMode: "svg", // ReattachConnections : true, //是否重新连接使用鼠标分离的线 // DragOptions: { cursor: "pointer", zIndex: 2000 }, DrapOptions: { cursor: "crosshair", zIndex: 2000 }, // 鼠标滑过线的样式 HoverPaintStyle: { stroke: "yellow", strokeWidth: 3, cursor: "pointer" }, }, 初始化 onMounted(async () => { // dom加载完成后才可以初始化jsplumb实例 await nextTick() // 创建jsPlumb实例 jsPlumbInstanceRef.value = jsPlumb.getInstance(); }); 创建端点: 创建端点的方式有三种: 3.1 makeSource/makeTarget:源端点和目标端点分别绑定,将绑定的dom元素当作端点,无连线时,无端点显示;有连线时才显示端点 const elem = document.getElementById(item.id); if (item.info.group === "list1") { jsPlumbInstanceRef.value.makeSource(elem, { anchor: "Continuous", // 左 上 右 下 allowLoopback: false, // 允许回连 maxConnections: 1, //最大连接数(-1表示不限制) }); } else { jsPlumbInstanceRef.value.makeTarget(elem, { anchor: "Continuous", allowLoopback: false, maxConnections: 1, }); }

3.2 connect:创建连线时,会同时创建前后两个端点和一条连线,连线断开时,两边端点也会消失,无法再次连接 (文档说配置deleteEndpointsOnDetach:true可以在删除连线时保留端点,但是实际操作时配置未生效)

data.lineList.forEach((item) => { jsPlumbInstanceRef.value.connect({ source: item.sourceId, target: item.targetId, deleteEndpointsOnDetach:true, // 不生效,删除线后,端点依然消失了 }); });

3.3 addEndpoint【采用这种】:创建端点,可以绑定uuid,connect连接时可以通过uuid进行端点连线,防止connect多次创建两边的端点,导致遮挡,拖拽不生效问题

data.nodeList.forEach((item, index) => { jsPlumbInstanceRef.value.addEndpoint( item.id, { anchor: [item.info.group === "list1" ? "Right" : "Left"], maxConnections: 1, uuid: item.id, }, { isSource: item.info.group === "list1", // 是否可以作为源 isTarget: item.info.group === "list2", // 是否可以作为目标 maxConnections: 1, } ); }); // 通过uuid绑定端点连线 data.lineList.forEach((item) => { jsPlumbInstanceRef.value.connect({uuids: [item.sourceId, item.targetId]}); }); 给节点添加拖拽::不是给锚点添加拖拽,锚点本身可以拖拽 // 通过draggable给节点添加拖拽:不是给锚点添加拖拽,锚点本身可以拖拽 jsPlumbInstanceRef.value.draggable(item.id); 对操作进行批处理:处理期间不触发渲染 jsPlumbInstanceRef.value.batch(() => { // 进行操作 }) 等待实例渲染完成后进行操作 jsPlumbInstanceRef.value.ready(() => { // 进行操作 }) 进行事件绑定 //连线成功时触发 jsPlumbInstanceRef.value.bind("connection", connectLine); //连线断开时 触发 jsPlumbInstanceRef.value.bind("connectionDetached", connectLineDetached); //连接取消connectionAborted jsPlumbInstanceRef.value.bind( "connectionAborted", (conn, originalEvent) => { console.log("连接取消", conn, originalEvent); message.info("目标节点上已有关联属性,不支持该连接"); } ); //在连线上点击右键触发 jsPlumbInstanceRef.value.bind("contextmenu", (conn, originalEvent) => { console.log("点击右键", conn, originalEvent); }); //点击连线 jsPlumbInstanceRef.value.bind("click", (conn, originalEvent) => { console.log("click事件", conn, originalEvent); }); //超过端点数量触发 jsPlumbInstanceRef.value.bind("onMaxConnections", (conn, originalEvent) => { console.log("超过端点数量触发", conn, originalEvent); }); 实例方法 jsPlumbInstanceRef.value.repaintEverything(); // 重绘 jsPlumbInstanceRef.value.deleteEveryConnection(); // 断掉所有连线

总结:

// jsPlumb实例ready之后初始化一些设置 jsPlumbInstanceRef.value.ready(() => { // 导入准备好的jsPlumb配置,通过importDefaults对默认配置进行覆盖 jsPlumbInstanceRef.value.importDefaults(data.jsPlumbSetting); // 通过batch进行批处理操作:处理期间不触发渲染 jsPlumbInstanceRef.value.batch(() => { // 对节点进行配置:创建端点,进行连线 data.nodeList.forEach((item, index) => { jsPlumbInstanceRef.value.addEndpoint( item.id, { anchor: [item.info.group === "list1" ? "Right" : "Left"], maxConnections: 1, uuid: item.id, }, { isSource: item.info.group === "list1", // 是否可以作为源 isTarget: item.info.group === "list2", // 是否可以作为目标 maxConnections: 1, } ); }); data.lineList.forEach((item) => { jsPlumbInstanceRef.value.connect(item); }); }); }); jsPlumbInstanceRef.value.repaintEverything(); // 重绘 //连线时触发 存储连接信息 jsPlumbInstanceRef.value.bind("connection", connectLine); //连线断开时 触发 jsPlumbInstanceRef.value.bind("connectionDetached", connectLineDetached); //连接取消connectionAborted jsPlumbInstanceRef.value.bind( "connectionAborted", (conn, originalEvent) => { console.log("连接取消", conn, originalEvent); message.info("目标节点上已有关联属性,不支持该连接"); } ); //在连线上点击右键触发 jsPlumbInstanceRef.value.bind("contextmenu", (conn, originalEvent) => { console.log("点击右键", conn, originalEvent); }); //点击连线 jsPlumbInstanceRef.value.bind("click", (conn, originalEvent) => { console.log("click事件", conn, originalEvent); }); //超过端点数量触发 jsPlumbInstanceRef.value.bind("onMaxConnections", (conn, originalEvent) => { console.log("超过端点数量触发", conn, originalEvent); }); 问题汇总

Q1. 端点无法跟随窗口大小改变进行自适应 A1. 需要监听窗口大小变化,进行重绘,注意监听需要销毁

window.addEventListener('resize', () => { jsPlumbInstanceRef.value.repaintEverything(); // 重绘 })

Q2. 页面上下滚动时,端点不跟随滚动 A2. 端点是通过绝对定位的方式,跟随上一级相对定位的盒子进行定位,需要给包裹的容器盒子添加属性 position: relative 进行相对定位

Q3. 通过addEndpoint 创建端点之后,再使用connect进行连线,导致端点重复生成 A3. connect进行连线会同时生成两个端点和一条线,如果之前已有端点,可以通过端点的uuid创建连线,防止重复生成端点。(本文例子便是这种方式)

Q4. 排序后,对应连线不跟随端点位置变化,进行更新 A4. 连线未跟随端点绑定,需要手动进行重绘

Q5. 原连线可以进行拖拽,通过更新ConnectionsDetachable:false设置为不可拖拽,但原有端点仍可进行拖拽 A5. 配置发生变化后,已生成端点不会更新状态,需要先全部断开,再重新划线 。

Q6. 删除源数据后,端点及连线没有跟随变化,仍停留在原有位置 A6. 重新设置实例,端点及连线



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有